package iptux;

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.ListCellRenderer;
import java.awt.GridLayout;
import javax.swing.JMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.UIManager;
import baseclass.Configer;
import baseclass.FileInfo;
import baseclass.ImageListCellRenderer;
import iptux.IptuxUDPServer;
import iptux.Utils;
import baseclass.PalInfo;
import iptux.DialogPeer;

/**
 * Title: class Iptux<br>
 * Description: Iptux main class<br>
 * Copyright: MIT open source protocol<br>
 * @author cwll<cwll2009@126.com>
 * @version 1.0.0
 */
public class Iptux implements ActionListener{

	private JFrame frmJiptux;
	JList<Object> list;		//pal list control
	public ArrayList<IptuxUDPServer> UDPServerList = new ArrayList<IptuxUDPServer>();
	public ArrayList<IptuxTCPServer> TCPServerList = new ArrayList<IptuxTCPServer>();
	public ArrayList<FileInfo> sendFileList = new ArrayList<FileInfo>();
	public ArrayList<FileInfo> rcvFileList = new ArrayList<FileInfo>();
	//close these client socket before exit.
	ArrayList<Socket> clientSocketList = new ArrayList<Socket>();
	//model of the pal list control
	private Object[][] palListData = null;
	ArrayList<PalInfo> palList = new ArrayList<PalInfo>();
    private ArrayList<DialogPeer> dlgPeerList = new ArrayList<DialogPeer>();
    //store information of myself.
    PalInfo SelfInfo = new PalInfo();
    boolean Animate = false;
    Timer timer = new Timer(true);
    //the pal need animation when received message not read.
    ArrayList<PalInfo> palAnimList = new ArrayList<PalInfo>();
    //store the debug statue of the application, set this value in the initialization
    boolean isDebug = false;
    
    Configer configer = new Configer();
    MSGLogger msgLogger;
    
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Iptux window = new Iptux();
					window.frmJiptux.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Iptux() {
		initialize();
		SelfInfo.name = System.getProperty("user.name");
		startupUDPServers();
		startupTCPServers();
	}
	
	public void startupUDPServers(){
		ArrayList <String> iplist = Utils.GetLocalIPAddress();
		//startup udpservers, each ipaddress startup a udpserver
		IptuxUDPServer udpServer = null;
		for (String ip:iplist){
			//System.out.println("ip address:"+ip);
			try {
				udpServer = new IptuxUDPServer(ip,this);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("program exit with 0");
				System.exit(0);
			}
			udpServer.start();
			UDPServerList.add(udpServer);
		}
		for(IptuxUDPServer UDPSvr:UDPServerList){
			UDPSvr.BroadcastEntry();
		}
	}
	
	public void startupTCPServers(){
		ArrayList<String>  iplist = Utils.GetLocalIPAddress();
		//startup tcpservers, each ipaddress startup a tcpserver
		IptuxTCPServer tcpServer = null;
		for (String ip:iplist){
			//System.out.println("ip address:"+ip);
			try {
				tcpServer = new IptuxTCPServer(ip,this);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("program exit with 0");
				System.exit(0);
			}
			tcpServer.start();
			TCPServerList.add(tcpServer);
		}
	}
	
	/**
	 * Find chat dialog handler of the pal from DlgPeerList.
	 * @param palIPAddress	IP address of the pal
	 * @return	The dialog handler
	 */
	public DialogPeer findDialogPeer(String palIPAddress){
		DialogPeer dlg = null;
		for(DialogPeer dlgTmp:this.dlgPeerList){
			if (dlgTmp.pal.ipv4.equals(palIPAddress))
				dlg =  dlgTmp;
		}
		return dlg;
	}
	
	/**
	 * Append a pal handler to  palList.
	 * @param pal The handler to append.
	 */
	public void appendPal(PalInfo pal){
		if(this.findPal(pal.ipv4) != null)
			return;
		this.palList.add(pal);
		this.updatePalListUI();
	}
	
	/**
	 * Append a client socket handler to  client socket list.
	 * @param socket The handler to append.
	 */
	public void appendClientSocket(Socket socket){
		this.clientSocketList.add(socket);
	}
	
	/**
	 * Delete pal from palList.
	 * @param palIPAddress IP address of the pal
	 */
	public void deletePal(String palIPAddress){
		PalInfo TargetPal = null;
		for(PalInfo pal:this.palList){
			if(pal.ipv4.equals(palIPAddress))
				TargetPal = pal;
		}
		if(TargetPal != null){
			this.palList.remove(TargetPal);
		}
		this.updatePalListUI();
	}
	
	/**
	 * Update the pal list UI. This method use palListData as the data model.
	 */
	public void updatePalListUI(){
		palListData = new Object[this.palList.size()][3];
		byte[] buffer;

		for(int i=0;i<this.palList.size();i++){
			//get icon from jar file
			buffer = Utils.readImageFromJar(this.palList.get(i).iconfile);
			palListData[i][0] = new ImageIcon(buffer);
			palListData[i][1] = this.palList.get(i).name + "(" 
					+ this.palList.get(i).ipv4 + ")";
			palListData[i][2] = this.palList.get(i);
		}
		list.setListData(palListData);
	}
	
/*	private void updatePalListUI(Color animateItemColor){
		palListData = new Object[this.palList.size()][3];
		byte[] buffer;
		for(int i=0;i<this.palList.size();i++){
			//System.out.println(this.palList.get(i).iconfile);
			buffer = Utils.readImageFromJar(this.palList.get(i).iconfile);
			palListData[i][0] = new ImageIcon(buffer);
			palListData[i][1] = this.palList.get(i).name + "(" 
					+ this.palList.get(i).ipv4 + ")";
			palListData[i][2] = this.palList.get(i);
		}
		list.setListData(palListData);
	}*/
	
	/**
	 * Find the handler of a pal from palList.
	 * @param palIPAddress IP address of the pal
	 * @return handler of a pal
	 */
	public PalInfo findPal(String palIPAddress){
		if(this.palList.size() == 0){
			return null;
		}
		for (PalInfo pal:this.palList){
			if (pal.ipv4.equals(palIPAddress))
				return pal;
		}
		return null;
	}
	
	public FileInfo findSendFile(Long packetn, int fileid){
		//FileInfo fileInfo = null;
		for(FileInfo fileInfo:sendFileList){
/*			if (fileInfo.packetn.equals(packetn.toString()) && fileInfo.fileid.equals(Integer.valueOf(fileid))) {
				return fileInfo;
			}*/
			if (fileInfo.packetn == packetn) {
				//System.out.println("packetn found");
				if (fileInfo.fileid ==  fileid ) {
					//System.out.println("fileid found");
					return fileInfo;
				}
			}
			//return fileInfo;
		}
		return null;
	}
	
	/**
	 * Show the chat dialog of a pal. If not exist, create it.
	 * @param palIPAddress  IP address of the pal
	 * @return handler of the chat dialog
	 */
	public DialogPeer openDialogPeer(String palIPAddress){
		DialogPeer DlgPeel = findDialogPeer(palIPAddress);
		if (DlgPeel == null){
			DlgPeel = createDialogPeer(palIPAddress);
		}
		DlgPeel.setVisible(true);
		return DlgPeel;
	}
	
	/**
	 * Create chat dialog of a pal.
	 * @param palIPAddress  IP address of the pal
	 * @return handler of the chat dialog
	 */
	public DialogPeer createDialogPeer(String palIPAddress){
		DialogPeer DlgPeel = findDialogPeer(palIPAddress);
		if (DlgPeel == null){
			PalInfo pal = findPal(palIPAddress);
			DlgPeel = new DialogPeer(this,pal);
			this.dlgPeerList.add(DlgPeel);
			DlgPeel.setTitle("Chatting with " + pal.name + " On " + pal.ipv4);
		}
		return DlgPeel;
	}
	
	/**
	 * Mouse click event precesser of the main window
	 */
    public void mouseClickProcesser(MouseEvent e) {
        int index;
        
        //the pal list control.
        if (e.getSource() == list) {
			if (e.getClickCount() == 3) {
				// thrice click
			} else if (e.getClickCount() == 2) {
				// double click
				if(list.getModel().getSize() == 0){
					return;
				}
				index = list.locationToIndex(e.getPoint());
				PalInfo pal = (PalInfo) palListData[index][2];
				palAnimList.remove(pal);
				openDialogPeer(pal.ipv4);
			}
			if (e.isMetaDown()) {// 检测鼠标右键单击
				//
			}
        }

    }
    
    /**
     * Display a exit confirm dialog. 
     * Broadcast a exit message before exit.
     */
    public void exitConfirm(){
		int retval = JOptionPane.showConfirmDialog(frmJiptux, "Are you sure to exit?","Exit Jiptux",
				JOptionPane.YES_NO_OPTION);
		if (retval == JOptionPane.YES_OPTION){
			for(IptuxUDPServer UDPServer:UDPServerList){
				UDPServer.BroadcastExit();
			}
			this.configer.save();
			System.exit(0);
		}
    }
    
    /**
     * Append pal to animate list, if it is not in palAnimList.
     * @param pal
     */
    public void AnimatePal(PalInfo pal){
    	if(palAnimList.indexOf(pal) < 0){
    		palAnimList.add(pal);
    	}
    }
    /**
     * Startup the animation thread for message receive remind.
     */
    public void AnimatePalList(){
    	timer.schedule(new TimerTask(){
    	    @Override  
    	    public void run() {
    	    	Animate = !Animate; 
    	    	DoAnimation(Animate);
    	    } 	
    	},0,300);
    }
    public void DoAnimation(boolean Animate){
    	int[] animPalList = new int[]{-1,-1,-1,-1,-1,-1,-1,-1,-1};
    	int animCount = 0;
    	for(int i=0;i<palList.size();i++){
    		if(palAnimList.indexOf(palList.get(i)) >= 0){
    			animPalList[animCount] = i;
    			animCount++;
    		}
    	}
    	if(Animate){
    	//update UI,set blink item to icon A and text color A
    		ListCellRenderer renderer=new ImageListCellRenderer(animPalList,Color.BLUE);
    		list.setCellRenderer(renderer);
    	}else{
    	//update UI,set blink item to icon B and text color B
    		ListCellRenderer renderer=new ImageListCellRenderer(animPalList,Color.black);
    		list.setCellRenderer(renderer);
    	}
    }
    
	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frmJiptux = new JFrame();
		ImageIcon image = new ImageIcon(Utils.readImageFromJar("/pixmaps/hicolor/48x48/apps/ip-tux.png")); 
		frmJiptux.setIconImage(image.getImage());
		frmJiptux.setTitle("Jiptux");
		frmJiptux.getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
		frmJiptux.setSize(275,539);
		frmJiptux.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				exitConfirm();
			}
		});
		frmJiptux.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		list = new JList<Object>();
		list.addMouseListener(new MouseAdapter(){
		    public void mouseClicked(MouseEvent e){  
		    	mouseClickProcesser(e);
		    } 
		});
		list.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
		ListCellRenderer renderer=new ImageListCellRenderer();
		list.setCellRenderer(renderer);
		frmJiptux.getContentPane().add(list);
		this.AnimatePalList();
		
		configer.load();
		isDebug = Utils.isDebug();
		if(configer.saveChatHistory == true){
			msgLogger = new MSGLogger();
		}
		
		JMenuBar menuBar = new JMenuBar();
		frmJiptux.setJMenuBar(menuBar);
		
		JMenu mnNewMenu = new JMenu("File");
		menuBar.add(mnNewMenu);
		
		JMenuItem mntmNewMenuItem = new JMenuItem("Dial up");
		mnNewMenu.add(mntmNewMenuItem);
		mntmNewMenuItem.addActionListener(this);
		
		JMenuItem mntmNewMenuItem_1 = new JMenuItem("Broadcast");
		mnNewMenu.add(mntmNewMenuItem_1);
		mntmNewMenuItem_1.addActionListener(this);
		
		JMenu mnNewMenu_1 = new JMenu("Tools");
		menuBar.add(mnNewMenu_1);
		
		JMenuItem mntmNewMenuItem_2 = new JMenuItem("Preference");
		mnNewMenu_1.add(mntmNewMenuItem_2);
		mntmNewMenuItem_2.addActionListener(this);
		
		JMenuItem mntmNewMenuItem_3 = new JMenuItem("Transmission");
		mnNewMenu_1.add(mntmNewMenuItem_3);
		mntmNewMenuItem_3.addActionListener(this);
		
		JMenuItem mntmNewMenuItem_4 = new JMenuItem("Update pal list");
		mnNewMenu_1.add(mntmNewMenuItem_4);
		mntmNewMenuItem_4.addActionListener(this);
		
		JMenu mnNewMenu_2 = new JMenu("Help");
		menuBar.add(mnNewMenu_2);
		
		JMenuItem mntmNewMenuItem_5 = new JMenuItem("About");
		mnNewMenu_2.add(mntmNewMenuItem_5);
		mntmNewMenuItem_5.addActionListener(this);
		
		JMenuItem mntmNewMenuItem_6 = new JMenuItem("Help and FAQ");
		mnNewMenu_2.add(mntmNewMenuItem_6);
		mntmNewMenuItem_6.addActionListener(this);
		
	}


	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		JMenuItem source = (JMenuItem)(arg0.getSource());
		
		//menuitem: broadcast 
		if(source.getText().equals("Broadcast")){
			for(IptuxUDPServer UDPSvr:UDPServerList){
				UDPSvr.BroadcastEntry();
			}
		}
		
		//menuitem: Dial up 
		if(source.getText().equals("Dial up")){
			String ipAddress = (String)JOptionPane.showInputDialog(
					frmJiptux,
                    "Please input the IP address of the pal.\n"
                    + "Like this 192.168.1.100", "Dial up a pal",
                    JOptionPane.PLAIN_MESSAGE, null, null, "");
			try {
				InetAddress address = InetAddress.getByName(ipAddress);
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				JOptionPane.showMessageDialog(frmJiptux,
						ipAddress + " is not exist or in error format.",
					    "Invalid address",
					    JOptionPane.ERROR_MESSAGE);
			}
			IptuxUDPServer.Dialup(ipAddress);
		}
		
		//menuitem: Preference
		if(source.getText().equals("Preference")){
			DialogConfig dlgConfig = new DialogConfig(this,"Settings",false);
			dlgConfig.setVisible(true);
		}
		
		//menuitem: Preference
		if(source.getText().equals("Transmission")){
			DialogFileTrans dlgFileTrans = new DialogFileTrans(this);
			dlgFileTrans.setModal(true);
			dlgFileTrans.setVisible(true);
		}
		
		//menuitem: Update pal list
		if(source.getText().equals("Update pal list")){
			palList.clear();
			updatePalListUI();
			for(IptuxUDPServer UDPSvr:UDPServerList){
				UDPSvr.BroadcastEntry();
			}
		}
	}
}
